﻿/*
 * Created by: 
 * Created: Tuesday, April 17, 2007
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Web.UI;
using Dune.Common.ControlFlow;
using Dune.Common.Utils;

namespace Dune.Common.TextTemplates.Impl.ASPNET
{
    public class TextEngine : ITextEngine
    {
        private const string VIRTUAL_DIR_PREFIX = "~/";
        private const string TEMPLATE_FILE_EXT = ".ascx";
        private string templatesDir;
        private bool needReloading = false;
        private ControlsFactory factory;
        private ParametersBinder parametersBinder = new ParametersBinder();
        private Assembly[] references;

        public TextEngine()
        {
        }

        public void Init()
        {
            InitInternal();
        }

        protected void InitInternal()
        {
            if (StringUtils.IsBlankOrNull(templatesDir))
                throw new ArgumentException("Property TemplatesDir must be not empty");

            factory = new ControlsFactory(templatesDir, needReloading, references);
        }

        public string TemplatesDir
        {
            get { return templatesDir; }
            set { templatesDir = value; }
        }


        public bool NeedReloading
        {
            get { return needReloading; }
            set { needReloading = value; }
        }


        public Assembly[] References
        {
            get { return references; }
            set { references = value; }
        }

        public string Render(string tmplName, IDictionary<string, object> contextObjects)
        {
            StringBuilder builder = new StringBuilder();
            RenderInternal(builder, tmplName, contextObjects, null);
            return builder.ToString();
        }

        #region ITextEngine Members

        public string Render(string tmplName, IDictionary<string, object> contextObjects,
                             IServiceProvider serviceProvider)
        {
            StringBuilder builder = new StringBuilder();
            RenderInternal(builder, tmplName, contextObjects, serviceProvider);
            return builder.ToString();
        }

        #endregion

        protected void RenderInternal(StringBuilder stringBuilder, string tmplName, IDictionary<string, object> contextObjects, IServiceProvider serviceProvider)
        {
            if (stringBuilder == null)
                throw new ArgumentException("stringBuilder");

            string templateVirtualPath = ResolveTemplatePath(tmplName);

            Control control = factory.Create(templateVirtualPath);
            parametersBinder.Bind(control, contextObjects);

            ControlRenderer renderer = new ControlRenderer(control);
            renderer.Render(stringBuilder, serviceProvider);
        }

        private static string ResolveTemplatePath(string tmplName)
        {
            if (StringUtils.IsBlankOrNull(tmplName))
                throw new ArgumentException("tmplName");

            string templateVirtualPath = tmplName.Trim();

            if (!templateVirtualPath.StartsWith(VIRTUAL_DIR_PREFIX))
                templateVirtualPath = VIRTUAL_DIR_PREFIX + templateVirtualPath;

            if (!templateVirtualPath.EndsWith(TEMPLATE_FILE_EXT))
                templateVirtualPath += TEMPLATE_FILE_EXT;
            return templateVirtualPath;
        }


        public ICollection<TemplateParametrInfo> GetTemplateParameters(string tmplName)
        {
            Type type = factory.GetControlType(ResolveTemplatePath(tmplName));
            return parametersBinder.GetParameters(type);
        }

        public ICollection<string> GetTemplates()
        {
            // TODO more valid code

            Assert.Check(!StringUtils.IsBlankOrNull(templatesDir));
            string[] files = Directory.GetFiles(templatesDir, "*" + TEMPLATE_FILE_EXT, SearchOption.AllDirectories);
            List<string> ret = new List<string>(files.Length);
            foreach (string fileName in files)
            {
                Assert.Check(fileName.StartsWith(templatesDir));
                Assert.Check(fileName.EndsWith(TEMPLATE_FILE_EXT));
                string templateName = fileName.Substring(templatesDir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? templatesDir.Length : templatesDir.Length + 1);
                templateName = templateName.Substring(0, templateName.Length - TEMPLATE_FILE_EXT.Length);
                if (!StringUtils.IsBlankOrNull(templateName))
                    ret.Add(templateName);
            }
            return ret;
        }
    }
}